home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GameStar 2004 April
/
Gamestar_61_2004-04_dvdb.iso
/
DVDStar
/
Editace
/
hltp.exe
/
{app}
/
Source Code
/
Half-Life Model Viewer
/
src
/
GlWindow.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1999-10-20
|
14KB
|
634 lines
//
// Half-Life Model Viewer (c) 1999 by Mete Ciragan
//
// file: GlWindow.cpp
// last modified: May 04 1999, Mete Ciragan
// copyright: The programs and associated files contained in this
// distribution were developed by Mete Ciragan. The programs
// are not in the public domain, but they are freely
// distributable without licensing fees. These programs are
// provided without guarantee or warrantee expressed or
// implied.
//
// version: 1.2
//
// email: mete@swissquake.ch
// web: http://www.swissquake.ch/chumbalum-soft/
//
#include <mx/mx.h>
#include <mx/mxMessageBox.h>
#include <mx/mxTga.h>
#include <mx/mxPcx.h>
#include <mx/mxBmp.h>
#include <mx/gl.h>
#include <GL/glu.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "GlWindow.h"
#include "StudioModel.h"
#include "ViewerSettings.h"
extern char g_appTitle[];
extern bool g_bStopPlaying;
GlWindow *g_GlWindow = 0;
vec3_t g_vright = { 50, 50, 0 }; // needs to be set to viewer's right in order for chrome to work
float g_lambert = 1.5;
GlWindow::GlWindow (mxWindow *parent, int x, int y, int w, int h, const char *label, int style)
: mxGlWindow (parent, x, y, w, h, label, style)
{
glDepthFunc (GL_LEQUAL);
if (!parent)
setVisible (true);
else
mx::setIdleWindow (this);
}
GlWindow::~GlWindow ()
{
mx::setIdleWindow (0);
loadTexture (0, 0);
loadTexture (0, 1);
}
int
GlWindow::handleEvent (mxEvent *event)
{
static float oldrx = 0, oldry = 0, oldtz = 50, oldtx = 0, oldty = 0;
static int oldx, oldy;
switch (event->event)
{
case mxEvent::Idle:
{
g_studioModel.SetBlending (0, 0.0);
g_studioModel.SetBlending (1, 0.0);
static float prev;
float curr = (float) mx::getTickCount () / 1000.0f;
if (!g_bStopPlaying)
g_studioModel.AdvanceFrame ((curr - prev) * g_viewerSettings.speedScale);
prev = curr;
if (!g_viewerSettings.pause)
redraw ();
return 1;
}
break;
case mxEvent::MouseDown:
{
oldrx = g_viewerSettings.rot[0];
oldry = g_viewerSettings.rot[1];
oldtx = g_viewerSettings.trans[0];
oldty = g_viewerSettings.trans[1];
oldtz = g_viewerSettings.trans[2];
oldx = event->x;
oldy = event->y;
g_viewerSettings.pause = false;
return 1;
}
break;
case mxEvent::MouseDrag:
{
if (event->buttons & mxEvent::MouseLeftButton)
{
if (event->modifiers & mxEvent::KeyShift)
{
g_viewerSettings.trans[0] = oldtx - (float) (event->x - oldx);
g_viewerSettings.trans[1] = oldty + (float) (event->y - oldy);
}
else
{
g_viewerSettings.rot[0] = oldrx + (float) (event->y - oldy);
g_viewerSettings.rot[1] = oldry + (float) (event->x - oldx);
}
}
else if (event->buttons & mxEvent::MouseRightButton)
{
g_viewerSettings.trans[2] = oldtz + (float) (event->y - oldy);
}
redraw ();
return 1;
}
break;
case mxEvent::KeyDown:
{
switch (event->key)
{
case 32:
{
int iSeq = g_studioModel.GetSequence ();
if (iSeq == g_studioModel.SetSequence (iSeq + 1))
{
g_studioModel.SetSequence (0);
}
}
break;
case 27:
if (!getParent ()) // fullscreen mode ?
mx::quit ();
break;
case 'g':
g_viewerSettings.showGround = !g_viewerSettings.showGround;
if (!g_viewerSettings.showGround)
g_viewerSettings.mirror = false;
break;
case 'h':
g_viewerSettings.showHitBoxes = !g_viewerSettings.showHitBoxes;
break;
case 'o':
g_viewerSettings.showBones = !g_viewerSettings.showBones;
break;
case '5':
g_viewerSettings.transparency -= 0.05f;
if (g_viewerSettings.transparency < 0.0f)
g_viewerSettings.transparency = 0.0f;
break;
case '6':
g_viewerSettings.transparency += 0.05f;
if (g_viewerSettings.transparency > 1.0f)
g_viewerSettings.transparency = 1.0f;
break;
case 'b':
g_viewerSettings.showBackground = !g_viewerSettings.showBackground;
break;
case 's':
g_viewerSettings.useStencil = !g_viewerSettings.useStencil;
break;
case 'm':
g_viewerSettings.mirror = !g_viewerSettings.mirror;
if (g_viewerSettings.mirror)
g_viewerSettings.showGround = true;
break;
case '1':
case '2':
case '3':
case '4':
g_viewerSettings.renderMode = event->key - '1';
break;
case '-':
g_viewerSettings.speedScale -= 0.1f;
if (g_viewerSettings.speedScale < 0.0f)
g_viewerSettings.speedScale = 0.0f;
break;
case '+':
g_viewerSettings.speedScale += 0.1f;
if (g_viewerSettings.speedScale > 5.0f)
g_viewerSettings.speedScale = 5.0f;
break;
}
}
break;
} // switch (event->event)
return 1;
}
void
drawFloor ()
{
if (g_viewerSettings.use3dfx)
{
glBegin (GL_TRIANGLE_STRIP);
glTexCoord2f (1.0f, 0.0f);
glVertex3f (100.0f, 100.0f, 0.0f);
glTexCoord2f (1.0f, 1.0f);
glVertex3f (100.0f, -100.0f, 0.0f);
glTexCoord2f (0.0f, 0.0f);
glVertex3f (-100.0f, 100.0f, 0.0f);
glTexCoord2f (0.0f, 1.0f);
glVertex3f (-100.0f, -100.0f, 0.0f);
glEnd ();
}
else
{
glBegin (GL_TRIANGLE_STRIP);
glTexCoord2f (0.0f, 0.0f);
glVertex3f (-100.0f, 100.0f, 0.0f);
glTexCoord2f (0.0f, 1.0f);
glVertex3f (-100.0f, -100.0f, 0.0f);
glTexCoord2f (1.0f, 0.0f);
glVertex3f (100.0f, 100.0f, 0.0f);
glTexCoord2f (1.0f, 1.0f);
glVertex3f (100.0f, -100.0f, 0.0f);
glEnd ();
}
}
void
setupRenderMode ()
{
if (g_viewerSettings.renderMode == RM_WIREFRAME)
{
glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
glDisable (GL_TEXTURE_2D);
glDisable (GL_CULL_FACE);
glEnable (GL_DEPTH_TEST);
}
else if (g_viewerSettings.renderMode == RM_FLATSHADED ||
g_viewerSettings.renderMode == RM_SMOOTHSHADED)
{
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
glDisable (GL_TEXTURE_2D);
glEnable (GL_CULL_FACE);
glEnable (GL_DEPTH_TEST);
if (g_viewerSettings.renderMode == RM_FLATSHADED)
glShadeModel (GL_FLAT);
else
glShadeModel (GL_SMOOTH);
}
else if (g_viewerSettings.renderMode == RM_TEXTURED)
{
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
glEnable (GL_TEXTURE_2D);
glEnable (GL_CULL_FACE);
glEnable (GL_DEPTH_TEST);
glShadeModel (GL_SMOOTH);
}
}
void
GlWindow::draw ()
{
glClearColor (g_viewerSettings.bgColor[0], g_viewerSettings.bgColor[1], g_viewerSettings.bgColor[2], 0.0f);
if (g_viewerSettings.useStencil)
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
else
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport (0, 0, w2 (), h2 ());
//
// show textures
//
if (g_viewerSettings.showTexture)
{
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0.0f, (float) w2 (), (float) h2 (), 0.0f, 1.0f, -1.0f);
studiohdr_t *hdr = g_studioModel.getTextureHeader ();
if (hdr)
{
mstudiotexture_t *ptextures = (mstudiotexture_t *) ((byte *) hdr + hdr->textureindex);
float w = (float) ptextures[g_viewerSettings.texture].width * g_viewerSettings.textureScale;
float h = (float) ptextures[g_viewerSettings.texture].height * g_viewerSettings.textureScale;
glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
glLoadIdentity ();
glDisable (GL_CULL_FACE);
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
float x = ((float) w2 () - w) / 2;
float y = ((float) h2 () - h) / 2;
glDisable (GL_TEXTURE_2D);
glColor4f (1.0f, 0.0f, 0.0f, 1.0f);
glRectf (x - 2, y - 2, x + w + 2, y + h + 2);
glEnable (GL_TEXTURE_2D);
glColor4f (1.0f, 1.0f, 1.0f, 1.0f);
glBindTexture (GL_TEXTURE_2D, g_viewerSettings.texture + 3); //d_textureNames[0]);
glBegin (GL_TRIANGLE_STRIP);
glTexCoord2f (0, 0);
glVertex2f (x, y);
glTexCoord2f (1, 0);
glVertex2f (x + w, y);
glTexCoord2f (0, 1);
glVertex2f (x, y + h);
glTexCoord2f (1, 1);
glVertex2f (x + w, y + h);
glEnd ();
glPopMatrix ();
glClear (GL_DEPTH_BUFFER_BIT);
glBindTexture (GL_TEXTURE_2D, 0);
}
return;
}
//
// draw background
//
if (g_viewerSettings.showBackground && d_textureNames[0] && !g_viewerSettings.showTexture)
{
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f);
glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
glLoadIdentity ();
glDisable (GL_CULL_FACE);
glEnable (GL_TEXTURE_2D);
glColor4f (1.0f, 1.0f, 1.0f, 1.0f);
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
glBindTexture (GL_TEXTURE_2D, d_textureNames[0]);
glBegin (GL_TRIANGLE_STRIP);
glTexCoord2f (0, 0);
glVertex2f (0, 0);
glTexCoord2f (1, 0);
glVertex2f (1, 0);
glTexCoord2f (0, 1);
glVertex2f (0, 1);
glTexCoord2f (1, 1);
glVertex2f (1, 1);
glEnd ();
glPopMatrix ();
glClear (GL_DEPTH_BUFFER_BIT);
glBindTexture (GL_TEXTURE_2D, 0);
}
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective (65.0f, (GLfloat) w () / (GLfloat) h (), 1.0f, 4096.0f);
glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
glLoadIdentity ();
glTranslatef(-g_viewerSettings.trans[0], -g_viewerSettings.trans[1], -g_viewerSettings.trans[2]);
glRotatef (g_viewerSettings.rot[0], 1.0f, 0.0f, 0.0f);
glRotatef (g_viewerSettings.rot[1], 0.0f, 0.0f, 1.0f);
// setup stencil buffer
if (g_viewerSettings.useStencil)
{
/* Don't update color or depth. */
glDisable(GL_DEPTH_TEST);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
/* Draw 1 into the stencil buffer. */
glEnable(GL_STENCIL_TEST);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glStencilFunc(GL_ALWAYS, 1, 0xffffffff);
/* Now render floor; floor pixels just get their stencil set to 1. */
drawFloor();
/* Re-enable update of color and depth. */
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glEnable(GL_DEPTH_TEST);
/* Now, only render where stencil is set to 1. */
glStencilFunc(GL_EQUAL, 1, 0xffffffff); /* draw if ==1 */
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
}
g_vright[0] = g_vright[1] = g_viewerSettings.trans[2];
if (g_viewerSettings.mirror)
{
glPushMatrix ();
glScalef (1, 1, -1);
glCullFace (GL_BACK);
setupRenderMode ();
g_studioModel.DrawModel ();
glPopMatrix ();
}
if (g_viewerSettings.useStencil)
glDisable (GL_STENCIL_TEST);
setupRenderMode ();
glCullFace (GL_FRONT);
g_studioModel.DrawModel ();
//
// draw ground
//
if (g_viewerSettings.showGround)
{
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
glEnable (GL_DEPTH_TEST);
glEnable (GL_CULL_FACE);
if (g_viewerSettings.useStencil)
glFrontFace (GL_CW);
else
glDisable (GL_CULL_FACE);
glEnable (GL_BLEND);
if (!d_textureNames[1])
{
glDisable (GL_TEXTURE_2D);
glColor4f (g_viewerSettings.gColor[0], g_viewerSettings.gColor[1], g_viewerSettings.gColor[2], 0.7f);
glBindTexture (GL_TEXTURE_2D, 0);
}
else
{
glEnable (GL_TEXTURE_2D);
glColor4f (1.0f, 1.0f, 1.0f, 0.6f);
glBindTexture (GL_TEXTURE_2D, d_textureNames[1]);
}
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
drawFloor ();
glDisable (GL_BLEND);
if (g_viewerSettings.useStencil)
{
glCullFace (GL_BACK);
glColor4f (0.1f, 0.1f, 0.1f, 1.0f);
glBindTexture (GL_TEXTURE_2D, 0);
drawFloor ();
glFrontFace (GL_CCW);
}
else
glEnable (GL_CULL_FACE);
}
glPopMatrix ();
}
int
GlWindow::loadTexture (const char *filename, int name)
{
if (!filename || !strlen (filename))
{
if (d_textureNames[name])
{
glDeleteTextures (1, (const GLuint *) &d_textureNames[name]);
d_textureNames[name] = 0;
if (name == 0)
strcpy (g_viewerSettings.backgroundTexFile, "");
else
strcpy (g_viewerSettings.groundTexFile, "");
}
return 0;
}
mxImage *image = 0;
char ext[16];
strcpy (ext, mx_getextension (filename));
if (!mx_strcasecmp (ext, ".tga"))
image = mxTgaRead (filename);
else if (!mx_strcasecmp (ext, ".pcx"))
image = mxPcxRead (filename);
else if (!mx_strcasecmp (ext, ".bmp"))
image = mxBmpRead (filename);
if (image)
{
if (name == 0)
strcpy (g_viewerSettings.backgroundTexFile, filename);
else
strcpy (g_viewerSettings.groundTexFile, filename);
d_textureNames[name] = name + 1;
if (image->bpp == 8)
{
mstudiotexture_t texture;
texture.width = image->width;
texture.height = image->height;
g_studioModel.UploadTexture (&texture, (byte *) image->data, (byte *) image->palette, name + 1);
}
else
{
glBindTexture (GL_TEXTURE_2D, d_textureNames[name]);
glTexImage2D (GL_TEXTURE_2D, 0, 3, image->width, image->height, 0, GL_RGB, GL_UNSIGNED_BYTE, image->data);
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
delete image;
return name + 1;
}
return 0;
}
void
GlWindow::dumpViewport (const char *filename)
{
#ifdef WIN32
redraw ();
int w = w2 ();
int h = h2 ();
mxImage *image = new mxImage ();
if (image->create (w, h, 24))
{
#if 0
glReadBuffer (GL_FRONT);
glReadPixels (0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, image->data);
#else
HDC hdc = GetDC ((HWND) getHandle ());
byte *data = (byte *) image->data;
int i = 0;
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
COLORREF cref = GetPixel (hdc, x, y);
data[i++] = (byte) ((cref >> 0)& 0xff);
data[i++] = (byte) ((cref >> 8) & 0xff);
data[i++] = (byte) ((cref >> 16) & 0xff);
}
}
ReleaseDC ((HWND) getHandle (), hdc);
#endif
if (!mxTgaWrite (filename, image))
mxMessageBox (this, "Error writing screenshot.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
delete image;
}
#endif
}